#ifndef __LSV_GC_INTERNAL_H
#define __LSV_GC_INTERNAL_H

#include "schedule.h"

#include "lsv_gc.h"

int __lsv_gc_logctrl_cmp(const void *_logctrl, const void *_chunkid);

int lsv_gc_logctrl_create(lsv_volume_proto_t *lsv_info,
                          int for_gc,
                          lsv_log_proto_t log_ptoto,
                          lsv_gc_logctrl_t **logctrl);

void lsv_gc_logctrl_free(lsv_volume_proto_t *lsv_info, lsv_gc_logctrl_t *logctrl);

void __lsv_gc_logctrl_free(void *logctrl);

static inline int lsv_gc_logctrl_is_inactive(const lsv_gc_logctrl_t *logctrl) {
        return logctrl->lp_bm.inactive_page_count == logctrl->head.page_count;
}


int lsv_gc_add_to_check_queue_batch(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_count, lsv_u32_t *chunk_id_array,
                lsv_u8_t add_type);

/**
 * 目前，只处理valueup task
 *
 * @param lsv_info
 * @param gc_arg
 * @return
 */
int lsv_gc_offer(lsv_volume_proto_t *lsv_info, lsv_gc_arg_t *gc_arg);


/**
 * @todo chunk_offset没有利用起来
 *
 * @param lsv_info
 * @param chunk_id
 * @param chunk_offset
 * @return
 */
int lsv_gc_do_valueup(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, lsv_u32_t chunk_offset);

int lsv_gc_fullgc_offer(lsv_volume_proto_t *lsv_info);

int lsv_gc_fullgc(lsv_volume_proto_t *lsv_info);


void lsv_gc_log_free(lsv_volume_proto_t* lsv_info, lsv_u32_t log_chkid);

/**
 * @brief add to head
 *
 * @param check_queue
 * @param logctrl
 */
void _lsv_gc_check_queue_push(lsv_gc_check_queue_t *check_queue, lsv_gc_logctrl_t* logctrl);

/**
 * @brief add to tail
 *
 * @param check_queue
 * @param logctrl
 */
void _lsv_gc_check_queue_offer(lsv_gc_check_queue_t *check_queue, lsv_gc_logctrl_t* logctrl);

/**
 * @brief pop from head
 *
 * @param check_queue
 * @param logctrl
 */
void _lsv_gc_check_queue_poll(lsv_gc_check_queue_t *check_queue, lsv_gc_logctrl_t** logctrl);

/**
 * @brief gc check, 查询bitmap，获取一个chunk内页的引用情况.
 *
 * @todo 该操作与卷的快照数量成线性关系, 效率方面需要再考虑
 *
 * @param lsv_info
 * @param logctrl
 * @return
 */
int lsv_gc_check(lsv_volume_proto_t *lsv_info, lsv_gc_logctrl_t* logctrl);

/**
 * @brief 在POLLFULL时，CQ多于此值，即满，才开始GC
 *
 * @param lsv_info
 * @return
 */
int _lsv_gc_check_queue_size(lsv_volume_proto_t *lsv_info);

int lsv_gc_heap_insert(lsv_volume_proto_t *lsv_info, lsv_gc_logctrl_t *logctrl);

void lsv_gc_heap_valueup(lsv_gc_heap_t *gc_heap, lsv_gc_logctrl_t *logctrl);


/**
 * @brief include gc merge.
 *
 * @param lsv_info
 * @param type
 * @param logctrl_
 * @return
 */
int lsv_gc_heap_do_gc(lsv_volume_proto_t *lsv_info, lsv_u8_t type, lsv_gc_logctrl_t **new_logctrl);

// -------------------------------------------------------------------
// -- old storage
// -------------------------------------------------------------------

int lsv_gc_old_storage_remove_and_add(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, int force);

/**
 * @brief chunk0.log_page_id，记录os相关元数据, 持久化os相关数据(包括ready chunk）
 *
 * @param lsv_info
 * @return
 */
int lsv_gc_old_storage_head_set(lsv_volume_proto_t *lsv_info);


#endif
